#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMessageBox>

#define SP4   "    "
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow) {
  ui->setupUi(this);
}

MainWindow::~MainWindow() {
  delete ui;
}

void MainWindow::on_btn_generate_clicked() {
  m_structNameList.clear();
  ui->textEdit_struct->clear();
  QString jsonData = ui->textEdit_json->toPlainText();
  QString rootStructName = ui->lineEdit_structName->text();
  m_integerValueType = ui->lineEdit_integerValueType->text();
  rootStructName = rootStructName.trimmed();
  if (jsonData.isEmpty() || rootStructName.isEmpty()) {
    QMessageBox::warning(this, tr("Warnning"), tr("json内容和结构体名称不允许为空"));
    return;
  }

  if (m_integerValueType.isEmpty())
    m_integerValueType = "int";

  m_structNameList.insert(rootStructName);
  // 字符串格式化为JSON
  QJsonParseError err_rpt;
  QJsonDocument root_document = QJsonDocument::fromJson(jsonData.toUtf8(), &err_rpt);
  if (err_rpt.error != QJsonParseError::NoError) {
    QMessageBox::warning(this, tr("Warnning"), tr("JSON格式错误"));
    std::cout << "JSON格式错误" << std::endl;
    return;
  }

  QString structStr;
  // 获取到Json字符串的根节点
  if (root_document.isObject()) {
    QString subObjectStr;
    QJsonObject subObject = root_document.object();
    parseObject(subObject, rootStructName, subObjectStr);
    structStr.insert(0, subObjectStr);
  } else if (root_document.isArray()) {
    QString subArryStr;
    QJsonArray subArry = root_document.array();
    parseArray(subArry, rootStructName, subArryStr);
    structStr.insert(0, subArryStr);
  }

  ui->textEdit_struct->append(structStr);
}

void MainWindow::parseObject(QJsonObject &jsonObject, const QString &structName, QString &outStructStr) {
  outStructStr = tr("struct %1 {\n").arg(structName);
  QStringList structMemberList;
  QStringList keyList = jsonObject.keys();
      foreach (QString key, keyList) {
      QJsonValue value = jsonObject.value(key);
      QJsonValue::Type type = value.type();
      switch (type) {
        case QJsonValue::Null:break;
        case QJsonValue::Bool:outStructStr.append(SP4);
          outStructStr.append(tr("%1 %2;\n").arg("bool").arg(key));
          structMemberList.append(key);
          break;
        case QJsonValue::Double:outStructStr.append(SP4);
          outStructStr.append(tr("%1 %2;\n").arg(m_integerValueType).arg(key));
          structMemberList.append(key);
          break;
        case QJsonValue::String:outStructStr.append(SP4);
          outStructStr.append(tr("%1 %2;\n").arg("std::string").arg(key));
          structMemberList.append(key);
          break;
        case QJsonValue::Array: {
          QString structName = convertToUpperCamel(key);
          structName = getValidStructName(structName);
          outStructStr.append(SP4);
          outStructStr.append(tr("std::vector<%1> %2;\n").arg(structName).arg(key));
          structMemberList.append(key);
          QString subArryStr;
          QJsonArray subArry = value.toArray();
          parseArray(subArry, structName, subArryStr);
          outStructStr.insert(0, subArryStr);
        }
          break;
        case QJsonValue::Object: {
          QString structName = convertToUpperCamel(key);
          structName = getValidStructName(structName);
          outStructStr.append(SP4);
          outStructStr.append(tr("%1 %2;\n").arg(structName).arg(key));
          structMemberList.append(key);
          QString subObjectStr;
          QJsonObject subObject = value.toObject();
          parseObject(subObject, structName, subObjectStr);
          outStructStr.insert(0, subObjectStr);
        }
          break;
        case QJsonValue::Undefined:break;
      }
    }//end foreach (QString key, keyList)

  outStructStr.append(SP4);
  //XPACK(O(id, name)); // 添加宏定义XPACK在结构体定义结尾
  outStructStr.append("XPACK(O(");
      foreach (QString mem, structMemberList) {
      outStructStr.append(mem);
      outStructStr.append(", ");
    }
  outStructStr.chop(2);//删除多余的", "
  outStructStr.append(")); // 添加宏定义XPACK在结构体定义结尾\n");
  outStructStr.append(tr("};\n\n"));
}

void MainWindow::parseArray(QJsonArray &jsonArray, const QString &structName, QString &outStructStr) {
  outStructStr.clear();
  if (jsonArray.isEmpty())
    return;

  outStructStr = tr("struct %1 {\n").arg(structName);
  QStringList structMemberList;
  QJsonValue oneValue = jsonArray.at(0);
  if (oneValue.isObject()) {
    QJsonObject jsonObject = oneValue.toObject();
    QStringList keyList = jsonObject.keys();
        foreach (QString key, keyList) {
        QJsonValue value = jsonObject.value(key);
        QJsonValue::Type type = value.type();
        switch (type) {
          case QJsonValue::Null:break;
          case QJsonValue::Bool:outStructStr.append(SP4);
            outStructStr.append(tr("%1 %2;\n").arg("bool").arg(key));
            structMemberList.append(key);
            break;
          case QJsonValue::Double:outStructStr.append(SP4);
            outStructStr.append(tr("%1 %2;\n").arg(m_integerValueType).arg(key));
            structMemberList.append(key);
            break;
          case QJsonValue::String:outStructStr.append(SP4);
            outStructStr.append(tr("%1 %2;\n").arg("std::string").arg(key));
            structMemberList.append(key);
            break;
          case QJsonValue::Array: {
            QString structName = convertToUpperCamel(key);
            structName = getValidStructName(structName);
            outStructStr.append(SP4);
            outStructStr.append(tr("std::vector<%1> %2;\n").arg(structName).arg(key));
            structMemberList.append(key);
            QString subArryStr;
            QJsonArray subArry = value.toArray();
            parseArray(subArry, structName, subArryStr);
            outStructStr.insert(0, subArryStr);
          }
            break;
          case QJsonValue::Object: {
            QString structName = convertToUpperCamel(key);
            structName = getValidStructName(structName);
            outStructStr.append(SP4);
            outStructStr.append(tr("%1 %2;\n").arg(structName).arg(key));
            structMemberList.append(key);
            QString subObjectStr;
            QJsonObject subObject = value.toObject();
            parseObject(subObject, structName, subObjectStr);
            outStructStr.insert(0, subObjectStr);
          }
            break;
          case QJsonValue::Undefined:break;
        }
      }//end foreach (QString key, keyList)
  }

  outStructStr.append(SP4);
  //XPACK(O(id, name)); // 添加宏定义XPACK在结构体定义结尾
  outStructStr.append("XPACK(O(");
      foreach (QString mem, structMemberList) {
      outStructStr.append(mem);
      outStructStr.append(", ");
    }
  outStructStr.chop(2);//删除多余的", "
  outStructStr.append(")); // 添加宏定义XPACK在结构体定义结尾\n");
  outStructStr.append(tr("};\n\n"));
}

//将结构体名称转换成大驼峰命名规则
QString MainWindow::convertToUpperCamel(const QString &srcStr) {
  QString tmp = srcStr.trimmed();
  if (tmp.isEmpty())
    return QString();

  QChar ch = tmp.at(0).toUpper();
  tmp.replace(0, 1, ch);
  return tmp;
}

//判断结构体名称是否重复，如果重复则在后面添加后缀
QString MainWindow::getValidStructName(const QString &oldName) {
  if (!m_structNameList.contains(oldName)) {
    m_structNameList.insert(oldName);
    return oldName;
  }

  int index = 2;
  QString newName = oldName;
  while (m_structNameList.contains(newName)) {
    newName = oldName + QString::number(index++);
  }

  m_structNameList.insert(newName);
  return newName;
}
